// This is the main DLL file.

#include "stdafx.h"

#include "DataReader.h"

DataReader::DataReader()
{
	string IniFilename(DataReaderIniFile);

	Initial(IniFilename, "");
}

DataReader::DataReader(string IniFilename)
{
	Initial(IniFilename, "");
}

DataReader::DataReader(string IniFilename, string input_file_direction)
{
	Initial(IniFilename, input_file_direction);
}

DataReader::~DataReader()
{
	Close();
}

void DataReader::Initial(string IniFilename, string input_file_direction)
{
	ifstream IniFileStream;
	string TempStr;

	IniFileStream.open(IniFilename.c_str(), ios::in);
	if(IniFileStream.fail())
	{
		cout << "DataReader error: DataReader ini file" << IniFilename << " can not be opened!" << endl;
		return;
	}

	Filename = "";
	Arrangement = DataReader::TuplePerLine;
	Format = DataReader::Normal;
	TerminationChar = ' ';
	KilledTuplePoint = 0;
	KilledAttPoint = 0;
	KilledLinePoint = 0;
	TupleNumber = AttNumber = 0;
	TupleCounter = AttCounter = LineCounter = 0;
	for(;;)
	{
		IniFileStream >> TempStr;
		if(IniFileStream.eof())
		{
			break;
		}
		if(TempStr == "SetFilename")
		{
			char InFilename[MaxStrlen + 1];

			IniFileStream.getline(InFilename, MaxStrlen);
			Filename = InFilename;
			for(; Filename[0] == ' ';)
			{
				Filename = Filename.substr(1, Filename.length() - 1);
			}
      Filename = input_file_direction + Filename;
		}
		else if(TempStr == "SetTupleNumber")
		{
			IniFileStream >> TupleNumber;
			if(TupleNumber <= 0)
			{
				cout << "DataReader error: TupleNumber is less than 0!" << endl;
				return;
			}
		}
		else if(TempStr == "SetAttNumber")
		{
			int i;

			IniFileStream >> AttNumber;
			if(AttNumber <= 0)
			{
				cout << "DataReader error: AttNumber is less than 0!" << endl;
				return;
			}
			DatatypeList.resize(AttNumber);
			for(i = 0; i < AttNumber; i++)
			{
				DatatypeList[i] = DataReader::Int32;
			}
		}
		else if(TempStr == "SetArrangement")
		{
			IniFileStream >> TempStr;
			if(TempStr == "TuplePerLine")
			{
				Arrangement = DataReader::TuplePerLine;
			}
			else if(TempStr == "SingleLine")
			{
				Arrangement = DataReader::SingleLine;
			}
			else
			{
				cout << "DataReader error: Undefined data arrangement " << TempStr << "! Use TuplePerLine." << endl;
				Arrangement = DataReader::TuplePerLine;
			}
		}
		else if(TempStr == "SetFormat")
		{
			IniFileStream >> TempStr;
			if(TempStr == "Normal")
			{
				Format = DataReader::Normal;
			}
			else if(TempStr == "Missing")
			{
				Format = DataReader::Missing;
			}
			else if(TempStr == "Sparse")
			{
				Format = DataReader::Sparse;
			}
			else
			{
				cout << "DataReader error: Undefined data format " << TempStr << "! Use normal format." << endl;
				Format = DataReader::Normal;
			}
		}
		else if(TempStr == "SetTerminationChar")
		{
			IniFileStream >> TempStr;
			if(TempStr == "Space")
			{
				TerminationChar = ' ';
			}
			else if(TempStr == "Tab")
			{
				TerminationChar = '\t';
			}
			else if(TempStr == "Comma")
			{
				TerminationChar = ',';
			}
			else
			{
				cout << "DataReader error: Illegal termination char '" << TempStr << "'! Use space as termination char." << endl;
				TerminationChar = ' ';
			}
		}
		else if(TempStr == "SetDatatype")
		{
			int i;
			int Begin, End;

			IniFileStream >> Begin >> End >> TempStr;
			for(i = Begin; i <= End; i++)
			{
				if(i < 0)
				{
					cout << "DataReader error: SetDatatype " << i << " < 0 !" << endl;
					continue;
				}
				if(i >= AttNumber)
				{
					cout << "DataReader error: SetDatatype " << i << " >= AttNumber " << AttNumber << " !" << endl;
					continue;
				}
				if(TempStr == "Int32")
				{
					DatatypeList[i] = DataReader::Int32;
				}
				else if(TempStr == "Double")
				{
					DatatypeList[i] = DataReader::Double;
				}
				else if(TempStr == "String")
				{
					DatatypeList[i] = DataReader::String;
				}
				else
				{
					cout << "DataReader error: Undefined datatype " << TempStr << "! Use Int32." << endl;
					DatatypeList[i] = DataReader::Int32;
				}
			}
		}
		else if(TempStr == "KillTuple")
		{
			int i;
			int Begin, End;

			IniFileStream >> Begin >> End;
			for(i = Begin; i <= End; i++)
			{
				if(i < 0)
				{
					cout << "DataReader error: KillTuple " << i << " < 0 !" << endl;
					continue;
				}
				if(i >= TupleNumber)
				{
					cout << "DataReader error: KillTuple " << i << " >= TupleNumber " << TupleNumber << " !" << endl;
					continue;
				}
				KilledTupleList.push_back(i);
			}
		}
		else if(TempStr == "KillAtt")
		{
			int i;
			int Begin, End;

			IniFileStream >> Begin >> End;
			for(i = Begin; i <= End; i++)
			{
				if(i < 0)
				{
					cout << "DataReader error: KillAtt " << i << " < 0 !" << endl;
					continue;
				}
				if(i >= AttNumber)
				{
					cout << "DataReader error: KillAtt " << i << " >= AttNumber " << AttNumber << " !" << endl;
					continue;
				}
				KilledAttList.push_back(i);
			}
		}
		else if(TempStr == "KillLine")
		{
			int i;
			int Begin, End;

			IniFileStream >> Begin >> End;
			for(i = Begin; i <= End; i++)
			{
				if(i < 0)
				{
					cout << "DataReader error: KillLine " << i << " < 0 !" << endl;
					continue;
				}
				KilledLineList.push_back(i);
			}
		}
		else if(TempStr.substr(0, 2) == "//")
		{
			char TempCharArr[MaxStrlen + 1];

			IniFileStream.getline(TempCharArr, MaxStrlen);
		}
		else
		{
			cout << "DataReader error: Undefined command " << TempStr << "!" << endl;
		}
	}
	IniFileStream.close();

	sort(KilledTupleList.begin(), KilledTupleList.end());
	sort(KilledAttList.begin(), KilledAttList.end());
	sort(KilledLineList.begin(), KilledLineList.end());
}

bool DataReader::Open(void)
{
	In.open(Filename.c_str(), ios::in);
	return(!Fail());
}

void DataReader::Close(void)
{
	In.close();
}

bool DataReader::Fail(void)
{
	if(In.fail())
	{
		cout << "DataReader error: Input file " << Filename << " can not be opened!" << endl;
		return(true);
	}
	return(false);
}

bool DataReader::SkipLine(void)
{
	char TempCharArr[MaxStrlen + 1];

	if(Fail())
	{
		return(false);
	}
	for(;;)
	{
		In.getline(TempCharArr, MaxStrlen);
		if(In.eof())
		{
			return(false);
		}
		if(!In.fail())
		{
			break;
		}
		In.clear();
	}
	LineCounter++;
	return(true);
}

int DataReader::GetTupleNumber(void)
{
	return(TupleNumber);
}

int DataReader::GetAttNumber(void)
{
	return(AttNumber);
}
